/*
 * TreatmentRecord.java
 * 
 * @version 1.0, March 10, 2011
 * CS 2340 Team 10: Cyberdyne Systems
 */

package edu.gatech.oad.cyberdoc.domain;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.json.JSONException;
import org.json.JSONObject;

import edu.gatech.oad.cyberdoc.database.DatabaseSerializable;

/**
 * Contains the details of the Treatment Record.
 * 
 * TODO Add accessor methods to hide the TreatmentRecordInfo instance.
 * 
 * @author Miles Gantt
 * @version 1.0, March 11, 2011
 */
public class TreatmentRecord implements DatabaseSerializable {

	/**
	 * The logger for this class.
	 */
	private static final Logger LOG;

	/**
	 * All TreatmentRecord objects, mapped from ID to instance.
	 */
	private static Map<Integer, TreatmentRecord> Instances;

	/**
	 * The next available ID number. This should be set updated by any program
	 * that overrides the default mechanism for setting IDs.
	 */
	private static int NextId = 0;

	/**
	 * This TreatmentRecord's info.
	 */
	private TreatmentRecordInfo info;

	/**
	 * This TreatmentRecord's id.
	 */
	private int id;

	/**
	 * Flag indicating whether or not this TreatmentRecord has been destroyed.
	 * If it has been destroyed, a RuntimeException will be thrown.
	 */
	public boolean isAlive;

	static {
		LOG = Logger.getLogger("edu.gatech.oad.cyberdoc.domain."
				+ "TreatmentRecord");

		Instances = new HashMap<Integer, TreatmentRecord>();
	}

	/**
	 * Creates a new TreatmentRecord with the information and ID number
	 * provided.
	 * 
	 * If this constructor is called directly, the nextId must be updated before
	 * any calls to any other constructors.
	 * 
	 * @param id
	 *            The ID of this TreatmentRecord
	 * @param info
	 *            This TreatmentRecord's corresponding info class
	 */
	public TreatmentRecord(int id, TreatmentRecordInfo info) {
		if (Instances.containsKey(id)) {
			LOG.severe("The ID provided is not valid.");
			throw new IllegalStateException("The ID provided is not be valid.");
		}

		this.id = id;
		this.info = info;

		Instances.put(id, this);
		isAlive = true;
	}

	/**
	 * Creates an instance of this class from a JSONObject, as required by
	 * DatabaseSerializable.
	 * 
	 * @param object
	 *            The information from the database to use to create this User
	 * @throws JSONException
	 *             If a required field does not exist in the JSON object
	 */
	public TreatmentRecord(JSONObject object) throws JSONException {
		id = object.getInt("id");

		if (Instances.containsKey(id)) {
			LOG.severe("The ID provided is not valid.");
			throw new IllegalStateException("The ID provided is not be valid.");
		}

		object.remove("id");
		info = new TreatmentRecordInfo(object);

		Instances.put(id, this);
		isAlive = true;
	}

	/**
	 * Creates a new TreatmentRecord with information provided in
	 * TreatmentRecordInfo.
	 * 
	 * @param info
	 */
	public TreatmentRecord(TreatmentRecordInfo info) {
		this(NextId, info);

		NextId++; // $codepro.audit.disable assignmentToNonFinalStatic
	}

	/**
	 * Creates a new TreatmentRecord with default information.
	 */
	public TreatmentRecord() {
		this(new DefaultTreatmentRecordInfo());
	}

	/**
	 * Removes all TreatmentRecords from the system. This method should be used
	 * in testing only.
	 */
	public static void clear() {
		// TODO Restrict this method to testing only
		Instances.clear();
		NextId = 0;
	}

	/**
	 * Marks this TreatmentRecord as deleted.
	 */
	public void destroy() {
		isAlive = false;

		LOG.info("TreatmentRecord [id=" + id + "] has been destroyed.");
	}

	/**
	 * Marks this TreatmentRecord as no longer deleted.
	 */
	public void undestroy() {
		isAlive = true;

		LOG.info("TreatmentRecord [id=" + id + "] has been undestroyed.");
	}

	/**
	 * Sets the next available ID for a treatment record.
	 * 
	 * @param id
	 *            The next available ID
	 */
	public static void setNextId(int id) {
		NextId = id;
	}

	/**
	 * Returns the TreatmentRecord with the associated ID, if it exists, or
	 * false otherwise.
	 * 
	 * @param id
	 *            The ID to retrieve
	 * @return The TreatmentRecord associated with the given ID
	 */
	public static TreatmentRecord getTreatmentRecord(int id) {
		return Instances.get(id);
	}

	/**
	 * @return This TreatmentRecord's info
	 */
	public TreatmentRecordInfo getInfo() {
		return info;
	}

	/**
	 * Returns the value of the given field.
	 * 
	 * @param name
	 *            The name of the field
	 * @return The value of the field, or null if the name is not valid
	 */
	public Object getField(String name) {
		return info.getField(name);
	}

	/**
	 * @param info
	 *            This TreatmentRecord's new info
	 */
	public void setInfo(TreatmentRecordInfo info) {
		this.info = info;
	}

	/**
	 * Tostring method for Treatment Record.
	 * 
	 * @return String
	 */
	@Override
	public String toString() {
		return "TreatmentRecord #" + id + " [" + info + "]";
	}

	/**
	 * Returns this TreatmentRecord encoded in a JSONObject.
	 * 
	 * @return This object as a JSONObject
	 */
	@Override
	public JSONObject toJSONObject() {
		final JSONObject result = info.toJSONObject();

		try {
			result.put("id", id);
		} catch (JSONException e) {
			LOG.log(Level.SEVERE, "Unexpected exception.", e);
		}

		return result;
	}

	/**
	 * Returns the TreatmentRecord's ID.
	 * 
	 * @return This TreatmentRecord's unique ID.
	 */
	public int getID() {
		return id;
	}

	/**
	 * @return true if this TreatmentRecord is alive, or false otherwise
	 */
	public boolean isAlive() {
		return isAlive;
	}

	/**
	 * Returns a string that is unique to an instance of a class.
	 * 
	 * @return A unique identifier for this instance
	 */
	@Override
	public String getUniqueIdentifier() {
		return "" + id;
	}
}
